package cn.zpon.pay.demo.util;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ApacheHttpClient {

    private final static Logger log = LoggerFactory.getLogger(ApacheHttpClient.class);

    CloseableHttpClient httpclient = HttpClients.createDefault();
    private String charset = "utf-8";

    public ApacheHttpClient() {
        this(150, 2000, 2000, 5 * 1024 * 1024);
    }

    public ApacheHttpClient(int maxConPerHost, int conTimeOutMs, int soTimeOutMs, int maxSize) {
    }

    public HttpResponse get(String url) {
        return get(url, null, null);
    }

    public HttpResponse get(String url, Map<String, String> headers) {
        return get(url, headers, null);
    }

    public HttpResponse get(String url, Map<String, String> headers, OutputStream out) {
        HttpResponse response = new HttpResponse();
        CloseableHttpResponse cresponse = null;
        long time = System.currentTimeMillis();
        int size = 0;
        try {
            HttpGet httpGet = new HttpGet(url);

            if (headers != null && !headers.isEmpty()) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    httpGet.addHeader(entry.getKey(), entry.getValue());
                }
            }

            cresponse = httpclient.execute(httpGet);

            HttpEntity entity = cresponse.getEntity();
            response.setStatusCode(cresponse.getStatusLine().getStatusCode());
            if (out != null) {
                readData(out, entity.getContent());
            } else {
                out = new ByteArrayOutputStream();
                readData(out, entity.getContent());
                response.setResponse(new String(((ByteArrayOutputStream)out).toByteArray(), charset));
                size = response.getResponse().length();
            }
            EntityUtils.consume(entity);
        } catch (Exception e) {
            log.warn("GET error! url:{}", url, e);
        } finally {
            if (cresponse != null) {
                try {
                    cresponse.close();    
                } catch (Exception e2) {
                    // ignore
                }
            }
        }

        time = System.currentTimeMillis() - time;
        log.info("GET, url:{}, headers:{}, time:{}, size:{}, response:{}", url, headers, time, size, response);

        return response;
    }
    
    private int readData(OutputStream out, InputStream in) throws Exception {
        int size = 0;
        byte[] b = new byte[8096];
        int len = 0;
        while ((len = in.read(b)) > 0) {
            size += len;
            out.write(b, 0, len);
        }
        in.close();
        return size;
    }

    public HttpResponse post(String url, Map<String, String> nameValues) {
        return post(url, null, nameValues, null, null);
    }
    
    public HttpResponse post(String url, Map<String, String> headers, Map<String, String> nameValues, String body, byte[] binBody) {
        HttpResponse response = new HttpResponse();
        CloseableHttpResponse cresponse = null;
        long time = System.currentTimeMillis();
        try {
            HttpPost post = new HttpPost(url);
            if (headers != null && !headers.isEmpty()) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    post.addHeader(entry.getKey(), entry.getValue());
                }
            }
            
            if (nameValues != null && !nameValues.isEmpty()) {
                List<NameValuePair> list = new ArrayList<NameValuePair>(nameValues.size());
                for (Map.Entry<String, String> entry : nameValues.entrySet()) {
                    list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
                post.setEntity(new UrlEncodedFormEntity(list, "utf-8"));
            }
            if (body != null && !body.isEmpty()) {
                StringEntity strEntity = new StringEntity(body, "utf-8");
                post.setEntity(strEntity);
            }
            if (binBody != null) {
                post.setEntity(new ByteArrayEntity(binBody));
            }

            cresponse = httpclient.execute(post);

            HttpEntity entity = cresponse.getEntity();
            response.setStatusCode(cresponse.getStatusLine().getStatusCode());
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            readData(out, entity.getContent());
            response.setResponse(new String(((ByteArrayOutputStream)out).toByteArray(), charset));
            EntityUtils.consume(entity);
        } catch (Exception e) {
            log.warn("POST error! url:{}", url, e);
        } finally {
            if (cresponse != null) {
                try {
                    cresponse.close();    
                } catch (Exception e2) {
                    // ignore
                }
            }
        }

        time = System.currentTimeMillis() - time;
        log.info("POST, url:{}, headers:{}, nameValues:{}, body:{}, data:{}, time:{}, response:{}", url, headers, nameValues, body,
                binBody != null ? binBody.length : -1, time, response);

        return response;
    }
}
